import { _decorator, Component, Node, Prefab, instantiate, SpriteFrame, Input, Sprite, JsonAsset, Label, director, Graphics, UITransform, Vec3, tween, Color, UIOpacity, AudioClip } from 'cc';
import LianLianKan_GameData from './LianLianKan_GameData';
import { SSS_AudioManager } from 'db://assets/Script/Manager/SSS_AudioManager';
import { SSS_Consts } from 'db://assets/Script/Data/SSS_Consts';
import UI from 'db://assets/Script/Manager/UI';
import LianLianKan_WinPanel from './UI/LianLianKan_WinPanel';
import { SSS_GameData } from 'db://assets/Script/Data/SSS_GameData';
import { LianLianKan_Block } from './LianLianKan_Block';
import { LianLianKan_GameStorage } from './Data/LianLianKan_GameStorage';
import LianLianKan_GamePanel from './LianLianKan_GamePanel';
import { bdlMgr } from 'db://assets/Script/Manager/BundleManager_S';

const { ccclass, property } = _decorator;
type Point = { r: number, c: number };

@ccclass('LianLianKan')
export class LianLianKan extends Component {
        public static Instance: LianLianKan;

        @property(JsonAsset)
        level_json: JsonAsset = null!;
        @property(Node)
        Root_block: Node | null = null;
        @property(Prefab)
        blockPrefab: Prefab = null!;
        @property(Node)
        LineLayer: Node = null!;   // 场景中挂一个节点，带 Graphics + UITransform

        ROWS = 0;
        COLS = 0;
        board: number[][] = [];
        blocks: (LianLianKan_Block | null)[][] = [];

        firstSelect: LianLianKan_Block | null = null;

        onLoad() {
                LianLianKan.Instance = this;

                LianLianKan_GameStorage.initData();

                LianLianKan_GameData.InitData();

                this.addListeners();

                // this.initGame();

                const level = LianLianKan_GameData.Get_level();
                const shape = this.level_json.json.levels[level].shape;
                const count = SSS_GameData.All_Sprite_List.length;
                this.generateLevelWithShape(shape, count);

                console.log(`this.level_json.json`, this.level_json.json);
                console.log(`shape`, shape);


                this.ROWS = shape.length;
                this.COLS = shape[0].length;

                console.log(`this.ROWS`, this.ROWS);
                console.log(`this.COLS`, this.COLS);


                this.spawnBoard();
                // if (!this.findHint()) this.reshuffle();
        }

        start() {
                LianLianKan_GamePanel.Instance.ShowOn();
        }

        addListeners() {
        }

        Replay() {
                director.loadScene(SSS_Consts.SceneName.LianLianKan_Game_Scene);
        }

        generateLevelWithShape(shapeTemplate: number[][], typeCount: number) {
                const rows = shapeTemplate.length;
                const cols = shapeTemplate[0].length;

                const positions: { r: number; c: number }[] = [];
                for (let r = 0; r < rows; r++)
                        for (let c = 0; c < cols; c++)
                                if (shapeTemplate[r][c] === 1) positions.push({ r, c });

                let totalBlocks = positions.length;
                if (totalBlocks % 2 !== 0) totalBlocks--;

                const typeArray: number[] = [];
                for (let i = 0; i < totalBlocks / 2; i++) {
                        const t = Math.floor(Math.random() * typeCount);
                        typeArray.push(t, t);
                }

                for (let i = typeArray.length - 1; i > 0; i--) {
                        const j = Math.floor(Math.random() * (i + 1));
                        [typeArray[i], typeArray[j]] = [typeArray[j], typeArray[i]];
                }

                this.board = [];
                let idx = 0;
                for (let r = 0; r < rows; r++) {
                        const row: number[] = [];
                        for (let c = 0; c < cols; c++) {
                                if (shapeTemplate[r][c] === 1) row.push(typeArray[idx++]);
                                else row.push(-1);
                        }
                        this.board.push(row);
                }
        }

        spawnBoard() {
                this.blocks = [];
                const offsetX = -this.COLS * LianLianKan_GameData.CellWidth / 2 + LianLianKan_GameData.CellWidth / 2;
                const offsetY = this.ROWS * LianLianKan_GameData.CellHeight / 2 - LianLianKan_GameData.CellHeight / 2;

                for (let r = 0; r < this.ROWS; r++) {
                        const row: (LianLianKan_Block | null)[] = [];
                        for (let c = 0; c < this.COLS; c++) {
                                if (this.board[r][c] === -1) {
                                        row.push(null);
                                        continue;
                                }

                                const blockNode = instantiate(this.blockPrefab);
                                // blockNode.parent = this.node;
                                blockNode.parent = this.Root_block;

                                blockNode.setPosition(
                                        offsetX + c * LianLianKan_GameData.CellWidth,
                                        offsetY - r * LianLianKan_GameData.CellHeight
                                );

                                const block = blockNode.getComponent(LianLianKan_Block)!;
                                block.row = r;
                                block.col = c;
                                block.type = this.board[r][c];
                                block.RefreshSprite();

                                blockNode.on(Input.EventType.TOUCH_END, () => this.onClickBlock(block));
                                row.push(block);
                        }
                        this.blocks.push(row);
                }
        }

        onClickBlock(block: LianLianKan_Block) {


                // 第一次点击
                if (!this.firstSelect) {
                        let audio_root = `audio/tile click`;
                        bdlMgr.getRes<AudioClip>(SSS_Consts.BundleName.AUDIO, audio_root, AudioClip).then(res => {
                                SSS_AudioManager.Instance.playSFX(res, false);
                        });

                        this.firstSelect = block;
                        block.select(true);
                        return;
                }

                // 点击同一个，取消选择
                if (block === this.firstSelect) {
                        block.select(false);
                        this.firstSelect = null;
                        return;
                }

                const p1 = { r: this.firstSelect.row, c: this.firstSelect.col };
                const p2 = { r: block.row, c: block.col };

                const path = this.canConnect(p1, p2);
                if (path) {
                        // ✅ 配对成功
                        this.drawLine(path);
                        this.removePair(this.firstSelect, block);
                        this.firstSelect = null;

                        let audio_root = `audio/水音效1`;
                        bdlMgr.getRes<AudioClip>(SSS_Consts.BundleName.AUDIO, audio_root, AudioClip).then(res => {
                                SSS_AudioManager.Instance.playSFX(res, false);
                        });
                } else {
                        let audio_root = `audio/tile click`;
                        bdlMgr.getRes<AudioClip>(SSS_Consts.BundleName.AUDIO, audio_root, AudioClip).then(res => {
                                SSS_AudioManager.Instance.playSFX(res, false);
                        });

                        // ❌ 配对失败：旧的取消，新选中
                        this.firstSelect.select(false);   // 取消之前的
                        block.select(true);               // 设置新的为选中
                        this.firstSelect = block;         // 更新记录


                }
        }


        // onClickBlock(block: LianLianKan_Block) {
        //         if (!this.firstSelect) {
        //                 this.firstSelect = block;
        //                 block.select(true);
        //                 return;
        //         }

        //         if (block === this.firstSelect) {
        //                 block.select(false);
        //                 this.firstSelect = null;
        //                 return;
        //         }

        //         const p1 = { r: this.firstSelect.row, c: this.firstSelect.col };
        //         const p2 = { r: block.row, c: block.col };

        //         const path = this.canConnect(p1, p2);
        //         if (path) {
        //                 this.drawLine(path);
        //                 this.removePair(this.firstSelect, block);
        //         } else {
        //                 this.firstSelect.select(false);
        //         }

        //         this.firstSelect = null;
        // }

        removePair(b1: LianLianKan_Block, b2: LianLianKan_Block) {
                this.blocks[b1.row][b1.col] = null;
                this.blocks[b2.row][b2.col] = null;
                this.board[b1.row][b1.col] = -1;
                this.board[b2.row][b2.col] = -1;

                b1.node.active = false;
                b2.node.active = false;

                if (this.checkVictory()) {
                        this.scheduleOnce(() => {
                                this.onVictory();
                        }, 0.5);
                }
                else if (!this.findHint()) {
                        this.reshuffle();
                }
        }

        showHint() {
                const pair = this.findHint();
                if (pair) {
                        pair[0].hintEffect();
                        pair[1].hintEffect();
                } else console.log("无解，需要洗牌！");
        }

        checkVictory(): boolean {
                for (let r = 0; r < this.ROWS; r++)
                        for (let c = 0; c < this.COLS; c++)
                                if (this.blocks[r][c]) return false;
                return true;
        }

        reshuffle() {
                const list: number[] = [];
                for (let r = 0; r < this.ROWS; r++)
                        for (let c = 0; c < this.COLS; c++)
                                if (this.blocks[r][c]) list.push(this.blocks[r][c]!.type);

                for (let i = list.length - 1; i > 0; i--) {
                        const j = Math.floor(Math.random() * (i + 1));
                        [list[i], list[j]] = [list[j], list[i]];
                }

                let idx = 0;
                for (let r = 0; r < this.ROWS; r++) {
                        for (let c = 0; c < this.COLS; c++) {
                                const b = this.blocks[r][c];
                                if (b) {
                                        const newType = list[idx++];
                                        b.type = newType;
                                        this.board[r][c] = newType;
                                        //     b.sprite.spriteFrame = this.icons[newType];
                                        //     b.ResetSprite();
                                        b.RefreshSprite();
                                }
                        }
                }

                if (!this.findHint()) this.reshuffle();
        }

        /** ========== 连通性判断（返回路径） ========= */
        canConnect(p1: Point, p2: Point): Point[] | null {
                if (p1.r === p2.r && p1.c === p2.c) return null;
                if (this.board[p1.r][p1.c] !== this.board[p2.r][p2.c]) return null;

                const R = this.ROWS, C = this.COLS;
                const rows = R + 2, cols = C + 2;
                const pad: number[][] = Array.from({ length: rows }, () => Array(cols).fill(-1));
                for (let r = 0; r < R; r++) for (let c = 0; c < C; c++) pad[r + 1][c + 1] = this.board[r][c];

                const start = { r: p1.r + 1, c: p1.c + 1 };
                const target = { r: p2.r + 1, c: p2.c + 1 };
                const dirs = [{ dr: -1, dc: 0 }, { dr: 0, dc: 1 }, { dr: 1, dc: 0 }, { dr: 0, dc: -1 }];
                const INF = 999;
                const visited: number[][][] = Array.from({ length: rows }, () =>
                        Array.from({ length: cols }, () => [INF, INF, INF, INF])
                );

                const q: Array<{ r: number; c: number; dir: number; turns: number; path: Point[] }> = [];
                q.push({ r: start.r, c: start.c, dir: -1, turns: 0, path: [p1] });

                while (q.length) {
                        const cur = q.shift()!;
                        for (let d = 0; d < 4; d++) {
                                const dd = dirs[d];
                                const nextTurns = cur.dir === -1 || cur.dir === d ? cur.turns : cur.turns + 1;
                                if (nextTurns > 2) continue;

                                let nr = cur.r + dd.dr, nc = cur.c + dd.dc;
                                let path = [...cur.path];
                                while (nr >= 0 && nr < rows && nc >= 0 && nc < cols) {
                                        if (nr === target.r && nc === target.c) {
                                                path.push(p2);
                                                return path;
                                        }
                                        if (pad[nr][nc] !== -1) break;
                                        if (visited[nr][nc][d] > nextTurns) {
                                                visited[nr][nc][d] = nextTurns;
                                                q.push({ r: nr, c: nc, dir: d, turns: nextTurns, path: [...path, { r: nr - 1, c: nc - 1 }] });
                                        }
                                        nr += dd.dr;
                                        nc += dd.dc;
                                }
                        }
                }
                return null;
        }

        /** 画连线（坐标已修正：转换到 LineLayer 的局部坐标） */
        /** 画连线（改进版特效：描边+端点闪烁+渐隐消失） */
        drawLine(path: Point[]) {
                if (!path || path.length < 2) return;
                const g = this.LineLayer.getComponent(Graphics)!;
                g.clear();

                // 主线：红色
                g.lineWidth = 6;
                g.strokeColor = new Color(255, 60, 60, 255);

                for (let i = 0; i < path.length; i++) {
                        const localPos = this.gridToLineLayerPoint(path[i]);
                        if (i === 0) g.moveTo(localPos.x, localPos.y);
                        else g.lineTo(localPos.x, localPos.y);
                }
                g.stroke();

                // 白色描边（加粗一点）
                g.lineWidth = 10;
                g.strokeColor = new Color(255, 255, 255, 180);
                for (let i = 0; i < path.length; i++) {
                        const localPos = this.gridToLineLayerPoint(path[i]);
                        if (i === 0) g.moveTo(localPos.x, localPos.y);
                        else g.lineTo(localPos.x, localPos.y);
                }
                g.stroke();

                // 端点圆点
                const start = this.gridToLineLayerPoint(path[0]);
                const end = this.gridToLineLayerPoint(path[path.length - 1]);
                [start, end].forEach(pos => {
                        g.fillColor = new Color(255, 100, 100, 255);
                        g.circle(pos.x, pos.y, 10);
                        g.fill();
                });

                // 动画：闪烁两次再消失
                let opacity = this.LineLayer.getComponent(UIOpacity);
                opacity.opacity = 255;
                tween(opacity)
                        // .delay(0.1)
                        // .to(0.1, { opacity: 100 })
                        // .to(0.1, { opacity: 255 })
                        // .to(0.1, { opacity: 100 })
                        // .to(0.1, { opacity: 255 })
                        // .delay(0.1)
                        .to(0.5, { opacity: 0 })
                        .call(() => {
                                g.clear();
                                opacity.opacity = 255;
                        })
                        .start();
        }


        /** 把 grid (r,c) -> 先到世界坐标 -> 再转成 LineLayer 的局部坐标 */
        gridToLineLayerPoint(p: Point): Vec3 {
                // 与 spawnBoard 使用的位置公式保持一致
                const x = -this.COLS * LianLianKan_GameData.CellWidth / 2 + p.c * LianLianKan_GameData.CellWidth + LianLianKan_GameData.CellWidth / 2;
                const y = this.ROWS * LianLianKan_GameData.CellHeight / 2 - p.r * LianLianKan_GameData.CellHeight - LianLianKan_GameData.CellHeight / 2;
                const localPos = new Vec3(x, y, 0);

                // 转为世界坐标（相对于 this.node）
                const worldPos = this.node.getComponent(UITransform)!.convertToWorldSpaceAR(localPos);
                // 再把世界坐标转为 LineLayer 的局部坐标（Graphics 要求局部坐标）
                const lineLocal = this.LineLayer.getComponent(UITransform)!.convertToNodeSpaceAR(worldPos);
                return lineLocal;
        }

        findHint(): [LianLianKan_Block, LianLianKan_Block] | null {
                for (let r1 = 0; r1 < this.ROWS; r1++)
                        for (let c1 = 0; c1 < this.COLS; c1++) {
                                const b1 = this.blocks[r1][c1];
                                if (!b1) continue;
                                for (let r2 = r1; r2 < this.ROWS; r2++)
                                        for (let c2 = 0; c2 < this.COLS; c2++) {
                                                if (r1 === r2 && c1 === c2) continue;
                                                const b2 = this.blocks[r2][c2];
                                                if (!b2) continue;
                                                if (this.canConnect({ r: r1, c: c1 }, { r: r2, c: c2 })) return [b1, b2];
                                        }
                        }
                return null;
        }

        onVictory() {
                console.log("恭喜，胜利！");
                UI.Instance.CreatePanel_sub(`LianLianKan_Prefab`, `UI/LianLianKan_WinPanel`, LianLianKan_WinPanel);
        }

        上一关() {
                console.log(`上一关`);
                LianLianKan_GameData.Set_level(LianLianKan_GameData.Get_level() - 1);
                director.loadScene(SSS_Consts.SceneName.LianLianKan_Game_Scene);
        }
        下一关() {
                console.log(`下一关`);
                LianLianKan_GameData.Set_level(LianLianKan_GameData.Get_level() + 1);
                director.loadScene(SSS_Consts.SceneName.LianLianKan_Game_Scene);
        }
}